package com.idstaa.fillter;

import com.idstaa.bean.MethodInfo;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter, Runnable {
    Map<String, List<MethodInfo>> methodTimes = new ConcurrentHashMap<>();

    public TPMonitorFilter() {
        // 每隔5s打印线程使用情况
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(this, 1, 5, TimeUnit.SECONDS);
    }

    @Override
    public void run() {
        Set<String> strings = methodTimes.keySet();
        for (String methodName : strings) {
            List<MethodInfo> methodInfos = methodTimes.get(methodName);
            long tp90 = getTP(methodInfos, 0.9);
            long tp99 = getTP(methodInfos, 0.99);
            System.out.println(methodName + ":tp90=" + tp90);
            System.out.println(methodName + ":tp99=" + tp99);
        }
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result = null;
        Long takeTime = 0L;
        try {
            long startTime = System.currentTimeMillis();
            result = invoker.invoke(invocation);
            if (result.getException() instanceof Exception) {
                throw new Exception(result.getException());
            }
            takeTime = System.currentTimeMillis() - startTime;
        } catch (Exception e) {
            e.printStackTrace();
        }

        String methodName = invocation.getMethodName();
        List<MethodInfo> methodInfos = methodTimes.get(methodName);
        if (methodInfos == null) {
            methodInfos = new ArrayList<>();
            methodTimes.put(methodName, methodInfos);
        }
        methodInfos.add(new MethodInfo(invocation.getMethodName(), takeTime, System.currentTimeMillis()));
        return result;
    }

    private long getTP(List<MethodInfo> methodInfos, double rate) {
        ArrayList<MethodInfo> sortInfoList = new ArrayList<>();
        long endTime = System.currentTimeMillis();
        long startTime = System.currentTimeMillis() - 60000;

        for (MethodInfo methodInfo : methodInfos) {
            if (methodInfo.getEndTimes() > startTime && methodInfo.getEndTimes() < endTime) {
                sortInfoList.add(methodInfo);
            }
        }

        sortInfoList.sort(new Comparator<MethodInfo>() {
            @Override
            public int compare(MethodInfo o1, MethodInfo o2) {
                if (o1.getTimes() > o2.getEndTimes()) {
                    return 1;
                } else if (o1.getTimes() < o2.getTimes()) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });

        int index = (int) (sortInfoList.size() * rate);
        return sortInfoList.get(index).getTimes();
    }
}
